/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// @ts-nocheck
import { Configuration } from './config/Configuration'
import { LoggerContext } from './slf4j/loggercontext'
import { Level } from './Level'
import { AppenderEnum } from './AppenderEnum'
import { Appender } from './config/Appender'
import { ILogger } from './slf4j/ILogger'
import { ConsoleAppender } from './appender/ConsoleAppender'
import { FileAppender } from './appender/FileAppender'
import { RollingFileAppender } from './appender/RollingFileAppender'
import { DBAppender } from './appender/DBAppender'
import { SiftingAppender } from './appender/SiftingAppender'
import { SocketAppender } from './appender/SocketAppender'
import { SMTPAppender } from './appender/SMTPAppender'
import { HiLog } from './log/HiLog';
import { Formatter } from './formatter/Formatter';

const defaultConfigure: Configuration = {
    appender: [{
                   name: 'CONSOLE',
                   className: AppenderEnum.CONSOLE,
                   encoder: {
                       pattern: {
                           msg: '%date %level %logger %msg'
                       }
                   }
               }],
    root: {
        level: Level.DEBUG,
        appenderRef: {
            ref: 'CONSOLE'
        }
    }
}

export class Logger implements ILogger {
    private name: string
    private level: Level
    static ROOT_LOGGER_NAME = "ROOT"
    private loggerContext: LoggerContext
    private effectiveLevelInt: number
    private configure: Configuration = globalThis.configure
    private consoleAppender: ConsoleAppender
    private fileAppender: FileAppender
    private siftingAppender: SiftingAppender
    private dBAppender: DBAppender
    private socketAppender: SocketAppender
    private SMTPAppender: SMTPAppender
    private rollingFileAppender: RollingFileAppender
    private tag = ''
    private appenderArray: Array<Appender> = []

    constructor(name: string, loggerContext: LoggerContext) {
        this.name = name
        this.loggerContext = loggerContext
        if (!!!this.configure) {
            this.appenderArray = defaultConfigure.appender
            this.effectiveLevelInt = defaultConfigure.root.level.getLevelInt()
        } else {
            this.doConfigure()
        }
    }

    public trace(msg: string) {
        this.filterAndLog(Level.TRACE, msg)
    }

    public debug(msg: string) {
        this.filterAndLog(Level.DEBUG, msg)
    }

    public info(msg: string) {
        this.filterAndLog(Level.INFO, msg)
    }

    public warn(msg: string) {
        this.filterAndLog(Level.WARN, msg)
    }

    public error(msg: string) {
        this.filterAndLog(Level.ERROR, msg)
    }

    public fatal(msg: string) {
        this.filterAndLog(Level.FATAL, msg)
    }

    private filterAndLog(level: Level, msg: string) {
        this.level = level
        if (!!!this.configure) {
            if (this.effectiveLevelInt > this.level.getLevelInt()) {
                return
            }
            msg = Formatter.format(this.loggerContext, defaultConfigure.appender[0].encoder.pattern.msg, this.level.getLevelStr(), msg)
            HiLog.log(this.level.getLevelStr(), msg, this.tag)
        } else {
            for (let i in this.appenderArray) {
                switch (this.appenderArray[i].className) {
                    case AppenderEnum.CONSOLE:
                        this.consoleAppender.start(this.loggerContext, this.effectiveLevelInt, this.appenderArray, this.level, msg, this.tag)
                        break
                    case AppenderEnum.FILE:
                        this.fileAppender.start(this.loggerContext, this.effectiveLevelInt, this.appenderArray, this.level, msg)
                        break
                    case AppenderEnum.SMTP:
                        this.SMTPAppender.start(this.effectiveLevelInt, this.level, msg)
                        break
                    case AppenderEnum.SIFT:
                        this.siftingAppender.start(this.loggerContext, this.effectiveLevelInt, this.appenderArray, this.level, msg)
                        break
                    case AppenderEnum.DB:
                        this.dBAppender.start(this.loggerContext, this.effectiveLevelInt, this.appenderArray, this.level, msg)
                        break
                    case AppenderEnum.ROLLING_FILE:
                       this.rollingFileAppender.start(this.loggerContext, this.effectiveLevelInt, this.level, msg)
                        break
                    case AppenderEnum.SOCKET:
                        this.socketAppender.start(this.level, msg)
                        break
                }
            }
        }
    }

    private doConfigure() {
        if (!!!this.configure.logger) { //当没有配置logger时使用root
            this.effectiveLevelInt = this.configure.root.level.getLevelInt()
            for (let i in this.configure.appender) {
                if (this.configure.root.appenderRef.ref === this.configure.appender[i].name) {
                    this.appenderArray.push(this.configure.appender[i])
                }
            }
        } else { //logger
            for (let i in this.configure.logger) {
                if (this.loggerContext.getLoggerName() === this.configure.logger[i].name) {
                    this.effectiveLevelInt = this.configure.logger[i].level.getLevelInt()
                    for (let j in this.configure.appender) {
                        if (this.configure.logger[i].appenderRef.ref === this.configure.appender[j].name) {
                            this.appenderArray.push(this.configure.appender[j])
                        }
                    }
                }
            }
        }
        for (let i in this.appenderArray) {
            if (this.appenderArray[i].className === AppenderEnum.CONSOLE) {
                this.consoleAppender = new ConsoleAppender()
            }
            if (this.appenderArray[i].className === AppenderEnum.FILE) {
                this.fileAppender = new FileAppender(this.appenderArray[i])
            }
            if (this.appenderArray[i].className === AppenderEnum.SMTP) {
                this.SMTPAppender = new SMTPAppender()
                this.SMTPAppender.bind(this.appenderArray[i])
            }
            if (this.appenderArray[i].className === AppenderEnum.SIFT) {
                this.siftingAppender = new SiftingAppender(this.appenderArray[i])
            }
            if (this.appenderArray[i].className === AppenderEnum.DB) {
                this.dBAppender = new DBAppender(this.appenderArray[i])
            }
            if (this.appenderArray[i].className === AppenderEnum.ROLLING_FILE) {
                this.rollingFileAppender = new RollingFileAppender(this.appenderArray[i])
            }
            if (this.appenderArray[i].className === AppenderEnum.SOCKET) {
                this.socketAppender = new SocketAppender(this.appenderArray[i])
                this.socketAppender.bind(this.appenderArray[i])
            }
        }
    }

    public setLevel(level: Level) {
        this.level = level
        this.effectiveLevelInt = level.getLevelInt();
    }

    public setTag(tag: string) {
        this.tag = tag
    }
}